<?php
/**
 * Created by PhpStorm.
 * Author: 黑瞎子
 * Date: 2018/3/20
 * Time: 15:18
 */

namespace app\api\service;


use app\lib\enum\OrderStatusEnum;
use app\lib\exception\OrderException;
use app\lib\exception\TokenException;
use app\lib\exception\WeChatException;
use think\Exception;
use app\api\model\Order as OrderModel;
use app\api\service\Token as TokenService;
use app\api\service\Order as OrderService;
use think\Loader;
use think\Log;

Loader::import('WxPay.WxPay',EXTEND_PATH, '.Api.php');

class Pay
{
    private $orderID;
    private $orderNo;

    function __construct($orderID)
    {
        if (!$orderID){
            throw new Exception('订单号不能为NULL');
        }
        $this->orderID = $orderID;
    }

    //支付逻辑
    public function pay(){
        //对订单号进行业务验证
        //订单号不存在
        //订单号存在，但是订单号和当前用户不匹配
        //订单已支付
        //库存量检测
        //订单验证通过后生成并返回微信预订单信息
        $this->checkOrderValid();
        $orderService = new OrderService();
        $status = $orderService->checkOrderStock($this->orderID);
        if (!$status['pass']){
            return $status;
        }
        return $this->makeWxPreOrder($status['orderPrice']);
    }

    //生成微信预订单-调用微信接口
    //使用微信提供SDK配置预订单的参数
    private function makeWxPreOrder($totalPrice){
        $openid = TokenService::getCurrentTokenVar('openid');
        if (!$openid){
            throw new TokenException();
        }
        $wxOrderDate = new \WxPayUnifiedOrder();
        $wxOrderDate->SetOut_trade_no($this->orderNo);  //订单号
        $wxOrderDate->SetTrade_type('JSAPI');  //交易类型
        $wxOrderDate->SetTotal_fee($totalPrice * 100);  //订单总金额,单位是分，所以要*100
        $wxOrderDate->SetBody('鼎香楼');  //商品简单描述
        $wxOrderDate->SetOpenid($openid);  //用户的openid
        $wxOrderDate->SetNotify_url(config('secure.pay_back_rul'));  //异步接收微信支付的回调结果
        return $this->getPaySignature($wxOrderDate);
    }

    //调用微信内部的预订单接口，使用微信SDK把预订单信息传递到预订单接口
    private function getPaySignature($wxOrderDate){
        $wxOrder = \WxPayApi::unifiedOrder($wxOrderDate);
        if ($wxOrder['return_code'] != 'SUCCESS' || $wxOrder['result_code'] != 'SUCCESS' ){
            Log::record($wxOrder,'error');
            Log::record('获取预支付订单失败','error');
            throw new WeChatException([
                'msg' => $wxOrder['return_msg']
            ]);
        }
        //prepay_id 向用户推送消息时需要用到prepay_id，所以先保存到数据库的订单信息中
        $this->recordPreOrder($wxOrder);
        $signature = $this->sign($wxOrder);
        return $signature;
    }

    //从微信返回的预订单结果中获取客户端拉起微信支付需要的参数并返回，参数参考文档
    private function sign($wxOrder){
        $jsApiPayDate = new \WxPayJsApiPay();
        $jsApiPayDate->SetAppid(config('wx.app_id'));
        $jsApiPayDate->SetTimeStamp((string)time());

        $rand = md5(time() . mt_rand(0,1000));
        $jsApiPayDate->SetNonceStr($rand);
        $jsApiPayDate->SetPackage('prepay_id=' . $wxOrder['prepay_id']);
        $sign = $jsApiPayDate->MakeSign();  //签名可用微信SDK的方法生成
        $rawValues = $jsApiPayDate->GetValues();
        $rawValues['patSign'] = $sign;

        unset($rawValues['appId']);

        return $rawValues;
    }

    private function recordPreOrder($wxOrder){
        OrderModel::where('id', '=', $this->orderID)
            ->update(['prepay_id'=>$wxOrder['prepay_id']]);
    }

    //对订单号进行业务验证
    private function checkOrderValid(){
        $order = OrderModel::where('id','=',$this->orderID)
            ->find();
        if (!$order){
            throw new OrderException();
        }
        if (!TokenService::isValidOperate($order->user_id)){
            throw new TokenException([
                'msg' => '订单与用户不匹配',
                'errorCode' => 10003,
            ]);
        }
        if ($order->status != OrderStatusEnum::UNPAID ){
            throw new OrderException([
                'code' => 400,
                'msg' => '订单已支付过啦',
                'errorCode' => 80003,
            ]);
        }
        $this->orderNo = $order->order_no;
        return true;
    }
}